using System;
using System.Threading;

using TrueCode.Core.Diagnostics;

namespace TrueCode.Core.Threading
{
	public class WriterLock : IDisposable
	{
		#region Fields
		private bool _disposed;
		private readonly ReaderWriterLock	_readerWriterLock;
		private readonly LockCookie?		_upgradeCookie;
		#endregion

		#region .ctors
		private WriterLock( ReaderWriterLock readerWriterLock ) : this( readerWriterLock, -1 )
		{
		}

		private WriterLock( ReaderWriterLock readerWriterLock, int millisecondsTimeout )
		{
			#region Validation

			if(!DebugAssert.IsNotNull(readerWriterLock, "readerWriterLock"))
			{
				throw new Exception<ReaderWriterLock, ArgumentNullException>(new ArgumentNullException("readerWriterLock"));
			}
			#endregion

			_readerWriterLock = readerWriterLock;
			
			if( _readerWriterLock.IsReaderLockHeld )
			{
				_upgradeCookie = _readerWriterLock.UpgradeToWriterLock( millisecondsTimeout );
			}
			else
			{
				_readerWriterLock.AcquireWriterLock( millisecondsTimeout );
				_upgradeCookie = null;
			}
		}
		#endregion

		#region IDisposable Members
		public void Dispose( )
		{
			if( ! _disposed )
			{
				_disposed = true;
				if( _upgradeCookie == null )
				{
					_readerWriterLock.ReleaseWriterLock( );
				}
				else
				{
					LockCookie upgradeCookieValue = _upgradeCookie.Value;
					_readerWriterLock.DowngradeFromWriterLock( ref upgradeCookieValue );
				}
			}
		}
		#endregion

		public static IDisposable Lock(ReaderWriterLock access)
		{
			#region Validation
			ExceptionHelper.ThrowIfArgumentIsNull< WriterLock >(access, "access");
			#endregion

			return new WriterLock(access);
		}
	}
}
